﻿using SqlSugar;
using Zhao.Common.EnumEntity;
using Zhao.IServer;
using Zhao.IServer.Log;
using Zhao.IServer.Settlement;
using Zhao.Models.Entity;
using System.Transactions;
using Zhao.Models.DTO.Settlement;

namespace Zhao.Service.Settlement
{
    public class SettlementService : ISettlementService
    {
        private readonly ISqlSugarClient _db;
        private readonly ISettlementRecordService _settlementRecordService;
        private readonly ILogsServer _logger;

        public SettlementService(
            ISqlSugarClient db,
            ISettlementRecordService settlementRecordService,
            ILogsServer logger)
        {
            _db = db;
            _settlementRecordService = settlementRecordService;
            _logger = logger;
        }

        public async Task<SettlementResultDto> ExecuteSettlementAsync(DateTime settlementDate)
        {
            
            // 初始化结算结果
            var result = new SettlementResultDto
            {
                SettlementDate = settlementDate,
                SuccessfulCount = 0,
                FailedCount = 0,
                TotalAmount = 0,
                SettlementRecordIds = new List<int>()
            };

            try
            {
                // 结算日期的开始和结束时间
                var displayDate = settlementDate.Date.ToString("yyyy-MM-dd");

                // 1. 处理已完成的场地预约订单
                await SettleCompletedAppointments(displayDate, result);

                // 2. 处理已完成的活动订单
                await SettleCompletedActivities(displayDate, result);

                await _logger.Info($"结算完成，成功：{result.SuccessfulCount}笔，失败：{result.FailedCount}笔，总金额：{result.TotalAmount}");
                return result;
            }
            catch (Exception ex)
            {
                await _logger.Error($"结算过程发生错误: {ex.Message}");
                result.FailedCount++;
                return result;
            }
        }


        /// <summary>
        /// 结算已完成的场地预约
        /// </summary>
        /// <param name="displayDate"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        private async Task SettleCompletedAppointments(string displayDate, SettlementResultDto result)
        {
            try
            {
                // 查询指定日期内已完成、未结算的小程序场地预约
                var completedAppointments = await _db.Queryable<Appointments>()
                    .Where(a => 
                        a.Status == (short)AppointmentStatus.Completed && 
                        a.AppointmentType == (short)AppointmentTypeEnum.Apple &&
                        a.DisplayDate.Equals(displayDate)) // 小程序预约
                    .ToListAsync();

                await _logger.Info($"找到{completedAppointments.Count}条待结算的场地预约记录");

                if (completedAppointments.Count == 0)
                {
                    return;
                }

                // 收集所有预约ID，批量查询是否已结算
                var appointmentIds = completedAppointments.Select(a => a.AppointmentID).ToList();
                
                // 批量查询已结算记录
                var existingSettlements = await _db.Queryable<SettlementRecord>()
                    .Where(s => s.SettlementType == 3 && appointmentIds.Contains(s.RelatedID))
                    .ToListAsync();

                //获取已经结算过的场地预约 根据 RelatedID 关联的预约id进行存储存储进无序列组中
                var settledIds = existingSettlements.Select(s => s.RelatedID).ToHashSet();
                
                // 预先获取所有相关的订单信息 去重
                var orderIds = completedAppointments
                    .Where(a => a.OrderId.HasValue) //判断是否有值
                    .Select(a => a.OrderId.Value)
                    .Distinct()
                    .ToList();
                
                //查询相关订单
                var orders = await _db.Queryable<Orders>()
                    .Where(o => orderIds.Contains(o.OrderID) && o.Status == 3)
                    .ToListAsync();
                //根据 OrderID进行键值对的存储Orders对象
                var orderDict = orders.ToDictionary(o => o.OrderID);
                
                // 预先获取所有相关的场地信息
                var fieldIds = completedAppointments.Select(a => a.FieldID).Distinct().ToList();//获取场地id
                //查询场地信息
                var fields = await _db.Queryable<Fields>()
                    .Where(f => fieldIds.Contains(f.FieldID))
                    .ToListAsync();
                //根据场地id进行键值对的存储
                var fieldDict = fields.ToDictionary(f => f.FieldID);
                
                // 预先获取所有相关的场馆信息
                var venueIds = completedAppointments.Select(a => a.VenueID).Distinct().ToList();
                var venues = await _db.Queryable<Venues>()
                    .Where(v => venueIds.Contains(v.VenueID))
                    .ToListAsync();
                var venueDict = venues.ToDictionary(v => v.VenueID);
                
                // 预处理数据，准备待处理的预约及其对应的账单和结算记录
                var pendingAppointments = new List<(Appointments Appointment, Orders Order, Fields Field, Venues Venue)>();
                
                foreach (var appointment in completedAppointments)
                {
                    try
                    {
                        // 跳过已结算的记录
                        if (settledIds.Contains(appointment.AppointmentID))
                        {
                            await _logger.Info($"预约ID:{appointment.AppointmentID}已经结算过，跳过");
                            continue;
                        }
                        
                        // 验证关联的订单信息
                        if (!appointment.OrderId.HasValue)
                        {
                            await _logger.Info($"预约ID:{appointment.AppointmentID} 没有关联订单，跳过结算");
                            continue;
                        }

                        if (!orderDict.TryGetValue(appointment.OrderId.Value, out var order))
                        {
                            await _logger.Info($"未找到预约ID:{appointment.AppointmentID}关联的有效订单，跳过结算");
                            continue;
                        }
                        
                        // 获取场地信息和场馆信息
                        if (!fieldDict.TryGetValue(appointment.FieldID, out var field))
                        {
                            await _logger.Info($"未找到预约ID:{appointment.AppointmentID}关联的场地信息，跳过结算");
                            continue;
                        }

                        if (!venueDict.TryGetValue(appointment.VenueID, out var venue))
                        {
                            await _logger.Info($"未找到预约ID:{appointment.AppointmentID}关联的场馆信息，跳过结算");
                            continue;
                        }
                        
                        // 添加到待处理队列
                        pendingAppointments.Add((appointment, order, field, venue));
                    }
                    catch (Exception ex)
                    {
                        await _logger.Error($"预处理预约ID:{appointment.AppointmentID}时出错: {ex.Message}");
                        result.FailedCount++;
                    }
                }
                
                // 批量处理结算记录和账单
                if (pendingAppointments.Any())
                {
                    try
                    {
                        // 开始事务
                        await _db.Ado.CommitTranAsync();
                        
                        // 按场馆分组，更新场馆余额和创建账单
                        var appointmentsByVenue = pendingAppointments
                            .GroupBy(p => p.Venue.VenueID)
                            .ToDictionary(g => g.Key, g => g.ToList());

                        var settlementRecords = new List<SettlementRecord>();
                        
                        foreach (var venueGroup in appointmentsByVenue)
                        {
                            var venueId = venueGroup.Key;
                            var appointments = venueGroup.Value;
                            var totalAmount = appointments.Sum(a => a.Appointment.Price);
                            
                            // 1. 先创建Bill记录
                            var billNo = $"BILL{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(100, 999)}";
                            var bill = new Bill
                            {
                                VenuesId = venueId,
                                Amount = totalAmount,
                                Type = 1, // 收入
                                Status = 1, // 成功
                                CreatedAt = DateTime.Now,
                                Remark = $"场地预约收入 - {displayDate}，共{appointments.Count}笔"
                            };
                            
                            // 先插入账单获取ID
                            var billId = await _db.Insertable(bill).ExecuteReturnIdentityAsync();
                            
                            if (billId <= 0)
                            {
                                throw new Exception($"创建场馆ID:{venueId}的账单记录失败");
                            }
                            
                            // 2. 更新场馆余额
                            var updateResult = await _db.Updateable<Venues>()
                                .SetColumns(v => v.Balance == v.Balance + totalAmount)
                                .Where(v => v.VenueID == venueId)
                                .ExecuteCommandAsync();
                            
                            if (updateResult <= 0)
                            {
                                throw new Exception($"更新场馆ID:{venueId}的余额失败");
                            }
                            
                            // 3. 为每个预约创建结算记录，关联Bill ID
                            foreach (var item in appointments)
                            {
                                var settlementNo = $"STL{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(100, 999)}";
                                var settlementRecord = new SettlementRecord
                                {
                                    SettlementType = 3, // 预约结算
                                    RelatedID = item.Appointment.AppointmentID,
                                    VenueID = item.Appointment.VenueID,
                                    Amount = item.Appointment.Price,
                                    SettlementTime = DateTime.Now,
                                    Status = 1, // 成功
                                    CreatedAt = DateTime.Now,
                                    OrderID = item.Appointment.OrderId,
                                    Description = $"场地预约结算-{item.Field.FieldName}-{item.Appointment.DisplayDate}",
                                    SettlementNo = settlementNo,
                                    BillID = billId  // 关联账单ID
                                };
                                
                                settlementRecords.Add(settlementRecord);
                            }
                        }
                        
                        // 4. 批量插入结算记录
                        if (settlementRecords.Any())
                        {
                            var insertResult = await _db.Insertable(settlementRecords).ExecuteCommandAsync();
                            
                            if (insertResult <= 0)
                            {
                                throw new Exception("批量插入结算记录失败");
                            }
                            
                            // 获取新插入的结算记录ID
                            var insertedRecords = await _db.Queryable<SettlementRecord>()
                                .Where(s => settlementRecords.Select(r => r.SettlementNo).Contains(s.SettlementNo))
                                .ToListAsync();
                            
                            foreach (var record in insertedRecords)
                            {
                                result.SettlementRecordIds.Add(record.SettlementID);
                            }
                            
                            result.SuccessfulCount += settlementRecords.Count;
                            result.TotalAmount += settlementRecords.Sum(s => s.Amount);
                        }
                        
                        // 提交事务
                        await _db.Ado.CommitTranAsync();
                        
                        await _logger.Info($"批量结算场地预约成功，共{settlementRecords.Count}笔，总金额:{settlementRecords.Sum(s => s.Amount)}");
                    }
                    catch (Exception ex)
                    {
                        // 回滚事务
                        await _db.Ado.CommitTranAsync();
                        
                        result.FailedCount += pendingAppointments.Count;
                        await _logger.Error($"批量结算场地预约事务提交失败: {ex.Message}");
                    }
                }
            }
            catch (Exception ex)
            {
                await _logger.Error($"处理场地预约结算时出错: {ex.Message}");
            }
        }

        /// <summary>
        /// 结算已完成的活动
        /// </summary>
        /// <param name="displayDate">结算的日期</param>
        /// <param name="result"></param>
        /// <returns></returns>
        private async Task SettleCompletedActivities(string displayDate, SettlementResultDto result)
        {
            try
            {
                // 查询在指定日期内已完成的活动，只结算固定价格类型(PriceType=1)的活动
                var completedActivities = await _db.Queryable<Activities>()
                    .Where(a => 
                        a.Status == 5 && // 状态5为已结束
                        a.DisplayDate.Equals(displayDate) &&
                        a.PriceType == 1 // 只结算固定价格类型的活动，排除AA制和免费活动
                        )
                    .ToListAsync();

                await _logger.Info($"找到{completedActivities.Count}条待结算的固定价格活动记录");
                
                if (completedActivities.Count == 0)
                {
                    return;
                }
                
                // 收集所有活动ID
                var activityIds = completedActivities.Select(a => a.ActivityID).ToList();
                
                // 批量查询已结算记录
                var existingSettlements = await _db.Queryable<SettlementRecord>()
                    .Where(s => s.SettlementType == 1 && activityIds.Contains(s.RelatedID))
                    .ToListAsync();
                
                var settledIds = existingSettlements.Select(s => s.RelatedID).ToHashSet();
                
                // 预先获取所有活动报名信息
                var allMembers = await _db.Queryable<ActivityMembers>()
                    .Where(m => activityIds.Contains(m.ActivityId) && m.Status == 1)
                    .ToListAsync();
                
                var membersByActivity = allMembers.GroupBy(m => m.ActivityId)
                    .ToDictionary(g => g.Key, g => g.ToList());
                
                // 预处理活动数据
                var pendingActivities = new List<(Activities Activity, List<ActivityMembers> Members, decimal TotalAmount, int ParticipantCount)>();
                
                foreach (var activity in completedActivities)
                {
                    try
                    {
                        // 跳过已结算的记录
                        if (settledIds.Contains(activity.ActivityID))
                        {
                            await _logger.Info($"活动ID:{activity.ActivityID}已经结算过，跳过");
                            continue;
                        }
                        
                        // 验证活动报名信息
                        if (!membersByActivity.TryGetValue(activity.ActivityID, out var members) || !members.Any())
                        {
                            await _logger.Info($"活动ID:{activity.ActivityID}没有有效报名记录，跳过结算");
                            continue;
                        }
                        
                        // 计算参与人数和总结算金额
                        int participantCount = members.Sum(m => m.MaleNumber + m.FemaleNumber);
                        
                        // 计算总金额，考虑女性优惠
                        decimal totalAmount = 0;
                        foreach (var member in members)
                        {
                            // 男性按原价计算
                            decimal maleAmount = activity.Price * member.MaleNumber;
                            
                            // 女性按优惠价计算
                            decimal femaleAmount = 0;
                            if (activity.IsLadyDiscountEnabled && member.FemaleNumber > 0)
                            {
                                switch (activity.LadyDiscountType)
                                {
                                    case 1: // 固定价
                                        femaleAmount = activity.LadyDiscountValue.GetValueOrDefault() * member.FemaleNumber;
                                        break;
                                    case 3: // 折扣
                                        femaleAmount = activity.Price * activity.LadyDiscountValue.GetValueOrDefault() * member.FemaleNumber;
                                        break;
                                    case 5: // 减价
                                        decimal discountedPrice = activity.Price - activity.LadyDiscountValue.GetValueOrDefault();
                                        discountedPrice = discountedPrice < 0 ? 0 : discountedPrice;
                                        femaleAmount = discountedPrice * member.FemaleNumber;
                                        break;
                                    default:
                                        femaleAmount = activity.Price * member.FemaleNumber;
                                        break;
                                }
                            }
                            else
                            {
                                // 如果未启用女士优惠，按原价计算
                                femaleAmount = activity.Price * member.FemaleNumber;
                            }
                            
                            totalAmount += (maleAmount + femaleAmount);
                        }
                        
                        pendingActivities.Add((activity, members, totalAmount, participantCount));
                    }
                    catch (Exception ex)
                    {
                        await _logger.Error($"预处理活动ID:{activity.ActivityID}时出错: {ex.Message}");
                        result.FailedCount++;
                    }
                }
                
                // 批量处理活动结算
                if (pendingActivities.Any())
                {
                    try
                    {
                        // 开始事务
                        await _db.Ado.BeginTranAsync();
                        
                        // 按照场馆分组，为每个场馆创建账单
                        var venueGroups = pendingActivities.GroupBy(p => p.Activity.VenueID).ToList();
                        
                        foreach (var venueGroup in venueGroups)
                        {
                            var venueId = venueGroup.Key;
                            var activities = venueGroup.ToList();
                            var totalVenueAmount = activities.Sum(a => a.TotalAmount);
                            
                            // 创建场馆账单记录
                            var billNo = $"BILL{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(100, 999)}";
                            var activityNames = string.Join(", ", activities.Select(a => a.Activity.Title));
                            var totalParticipants = activities.Sum(a => a.ParticipantCount);
                            
                            var bill = new Bill
                            {
                                VenuesId = venueId,
                                Amount = totalVenueAmount,
                                Type = 1, // 收入
                                Status = 1, // 成功
                                CreatedAt = DateTime.Now,
                                Remark = $"活动收入 - {displayDate}, 活动: {activityNames}, 共{activities.Count}个活动, 总人数: {totalParticipants}"
                            };
                            
                            // 插入账单记录获取ID
                            var billId = await _db.Insertable(bill).ExecuteReturnIdentityAsync();
                            
                            if (billId <= 0)
                            {
                                await _logger.Error($"创建场馆ID:{venueId}的账单记录失败");
                                continue;
                            }
                            
                            // 更新场馆余额
                            var updateResult = await _db.Updateable<Venues>()
                                .SetColumns(v => v.Balance == v.Balance + totalVenueAmount)
                                .Where(v => v.VenueID == venueId)
                                .ExecuteCommandAsync();
                            
                            if (updateResult <= 0)
                            {
                                await _logger.Error($"更新场馆ID:{venueId}的余额失败");
                                continue;
                            }
                            
                            // 为每个活动创建单独的结算记录
                            foreach (var activityItem in activities)
                            {
                                try
                                {
                                    var activity = activityItem.Activity;
                                    var participantCount = activityItem.ParticipantCount;
                                    var activityAmount = activityItem.TotalAmount;
                                    
                                    var settlementNo = $"STL{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(100, 999)}";
                                    var settlementRecord = new SettlementRecord
                                    {
                                        SettlementType = 1, // 活动结算
                                        RelatedID = activity.ActivityID,
                                        VenueID = activity.VenueID,
                                        Amount = activityAmount,
                                        SettlementTime = DateTime.Now,
                                        Status = 1, // 成功
                                        CreatedAt = DateTime.Now,
                                        Description = $"活动结算 - {activity.Title}, 参与人数: {participantCount}, 单价: {activity.Price}, 总额: {activityAmount}",
                                        SettlementNo = settlementNo,
                                        BillID = billId  // 关联账单ID
                                    };
                                    
                                    // 添加单个结算记录
                                    var id = await _db.Insertable(settlementRecord).ExecuteReturnIdentityAsync();
                                    
                                    if (id <= 0)
                                    {
                                        await _logger.Error($"活动ID:{activity.ActivityID}结算记录添加失败");
                                        result.FailedCount++;
                                    }
                                    else
                                    {
                                        result.SettlementRecordIds.Add(id);
                                        result.SuccessfulCount++;
                                        result.TotalAmount += activityAmount;
                                        await _logger.Info($"活动ID:{activity.ActivityID} '{activity.Title}' 结算成功，人数:{participantCount}，单价:{activity.Price}，总金额:{activityAmount}");
                                    }
                                }
                                catch (Exception ex)
                                {
                                    await _logger.Error($"处理活动ID:{activityItem.Activity.ActivityID}的结算记录时出错: {ex.Message}");
                                    result.FailedCount++;
                                }
                            }
                        }
                        
                        // 提交事务
                        await _db.Ado.CommitTranAsync();
                        
                        await _logger.Info($"批量结算活动成功，共{result.SuccessfulCount}笔，总金额:{result.TotalAmount}");
                    }
                    catch (Exception ex)
                    {
                        // 回滚事务
                        await _db.Ado.RollbackTranAsync();
                        
                        result.FailedCount += pendingActivities.Count;
                        await _logger.Error($"批量结算活动事务提交失败: {ex.Message}");
                    }
                }
            }
            catch (Exception ex)
            {
                await _logger.Error($"处理活动结算时出错: {ex.Message}");
            }
        }
    }
}
